<?php

declare(strict_types=1);

namespace App\Traits\Model\Orders;

use App\Constants\Order\OrderCode;
use App\Constants\Payment\PaymentCode;
use App\Exception\InternalException;
use App\Job\App\Notify;
use App\Job\Order\Complete;
use App\Job\Order\Expire;
use App\Model\App\App;
use App\Model\Payment\Payment;
use App\Model\Shop\Shop;
use App\Model\Users\User as UserModel;
use App\Resource\Orders\OrderResource;
use App\Resource\Payment\PaymentResource;
use App\Scopes\Orders\Order as OrderScope;
use App\Model\Orders\OrderGood as OrderGoodModel;
use App\Service\Queue\DefaultQueue;
use App\Service\Queue\NotifyQueue;
use App\Utils\Other\Erp\Order\Push;
use App\Utils\Other\Gos\Goods\Good;
use App\Factory\Declaration\Factory;
use Hyperf\Collection\Arr;
use Hyperf\Context\Context;
use Hyperf\Database\Model\Events\Created;
use Hyperf\Database\Model\Events\Saved;
use Hyperf\Database\Model\Relations\BelongsTo;
use Hyperf\Database\Model\Relations\HasMany;
use App\Services\App\AppNotify as AppNotifyServices;
use Hyperf\Database\Model\Relations\HasOne;
use App\Model\Orders\OrderDeclare as OrderDeclareModel;
use App\Model\Orders\Invoice as InvoiceModel;
use App\Model\Orders\OrderAction as OrderActionModel;
use Hyperf\Stringable\Str;
use function Hyperf\Support\make;
use function Hyperf\Coroutine\defer;
use function Hyperf\Config\config;

trait Order
{
    /**
     * The "booting" method of the model.
     */
    protected function boot():void
    {
        parent::boot();
        static::addGlobalScope(new OrderScope);
    }

    /**
     * 设置店铺
     * @param $value
     */
    public function setShopIdAttribute($value)
    {
        if (!$value) {
            $value = match (getApp()) {
                'api' => getShop('id')
            };
        }

        $this->attributes['shop_id'] = $value;

        switch (getApp()) {
            case 'api':
                $this->fill([
                    'app_id' => Context::get('appModel')->id
                ]);
                break;
        }
    }

    /**
     * 设置订单号
     * @param $value
     */
    public function setNoAttribute($value)
    {
        if (!$value) {
            $value = $this->getNo();
        }

        $this->attributes['no'] = $value;
    }

    /**
     * 设置订单结束日期
     * @param $value
     */
    public function setTimeExpireAttribute($value)
    {
        if (!$value) {
            $value = date('Y-m-d H:i:s', strtotime('+24 hours'));
        }

        $this->attributes['time_expire'] = $value;
    }

    /**
     * 关联订单商品
     * @return HasMany
     */
    public function goods():HasMany
    {
        return $this->hasMany(OrderGoodModel::class);
    }

    /**
     * 关联用户
     * @return BelongsTo
     */
    public function user():BelongsTo
    {
        return $this->belongsTo(UserModel::class);
    }

    /**
     * 关联店铺
     * @return BelongsTo
     */
    public function shop():BelongsTo
    {
        return $this->belongsTo(Shop::class);
    }

    /**
     * 关联应用
     * @return BelongsTo
     */
    public function app():BelongsTo
    {
        return $this->belongsTo(App::class);
    }

    /**
     * 申报
     * @return HasOne
     */
    public function declares():HasOne
    {
        return $this->hasOne(OrderDeclareModel::class);
    }

    /**
     * 获取发货单
     * @return HasMany
     */
    public function invoice():HasMany
    {
        return $this->hasMany(InvoiceModel::class);
    }

    /**
     * 关联订单操作记录
     * @return HasMany
     */
    public function action():HasMany
    {
        return $this->hasMany(OrderActionModel::class);
    }

    /**
     * 关联支付单
     * @return HasMany
     */
    public function payment():HasMany
    {
        return $this->hasMany(Payment::class, 'order_no', 'no');
    }

    /**
     * 获取状态描述
     * @return string
     */
    public function getStatusTextAttribute():string
    {
        return OrderCode::getStatusMessage($this->status);
    }

    /**
     * 获取支付状态描述
     * @return string
     */
    public function getPayStatusTextAttribute():string
    {
        return OrderCode::getPayStatusMessage($this->pay_status);
    }

    /**
     * 新增后操作
     * @param Created $created
     */
    public function created(Created $created)
    {
        /** @var static $model */
        $model = $created->getModel();
        $model->addAction('订单创建', '您提交了订单, 请等待付款!');

        /** @var DefaultQueue $defaultQueue */
        $defaultQueue = make(DefaultQueue::class);
        $defaultQueue->push([$model->id], Expire::class, strtotime($model->time_expire)-time());
    }

    /**
     * 新增操作
     * @param string $remark
     * @param string $desc
     */
    public function addAction(string $remark='', string $desc='')
    {
        try {
            $userId = $this->user_id;
            $userType = 'user';
            switch (getApp()) {
                case 'safepay':
                    $userId = $this->shop_id;
                    $userType = 'shop';
                    break;
            }

            $this->action()->create([
                'user_id' => $userId,
                'user_type' => $userType,
                'shop_id' => $this->shop_id,
                'status' => $this->status??1,
                'pay_status' => $this->pay_status??1,
                'is_shipping' => in_array($this->status, [OrderCode::STATUS_PENDING_RECEIVED, OrderCode::STATUS_RECEIVED, OrderCode::STATUS_COMPLETE])?1:0,
                'remark' => $remark,
                'desc' => $desc
            ]);
        } catch (\Throwable $throwable) {
            logs($throwable->getMessage());
            logs($throwable->getTraceAsString());
        }
    }

    /**
     * 重新回调
     */
    public function notify():void
    {
        /** @var $this $model */
        $model = $this;
        /** @var App $appModel */
        $appModel = $model->app;
        if (!$appModel->payment_notify) { // 如果配置了支付回调地址
            return ;
        }

        /** @var string $scene 场景 */
        $scene = match ($model->pay_status) {
            OrderCode::PAY_STATUS_PAID => 'payment',
            OrderCode::PAY_STATUS_REFUND => 'refund',
            default => null
        };
        if (null === $scene && $model->status === OrderCode::STATUS_PENDING_RECEIVED) {
            $scene = 'delivery';
        }
        if (null === $scene) return ;

        $body = [
            'no' => $model->no,
            'merchant_no' => $model->merchant_no,
            'transaction_id' => $model->transaction_id,
            'paid_no' => $model->paid_no,
            'paid_amount' => $model->paid_amount,
            'status' => $model->status,
            'status_text' => $model->status_text,
            'pay_status' => $model->pay_status,
            'pay_status_text' => $model->pay_status_text,
            'scene' => $scene,
            'attach' => $model->attach,
            'source' => $model->source
        ];

        switch ($scene) {
            case 'refund':
                /** @var Payment $refundModel */
                $refundModel = $model->payment()
                    ->where('type', PaymentCode::TYPE_REFUND)
                    ->whereNotNull('process_at')
                    ->firstOrFail();
                $body['refund_amount'] = $refundModel->amount;
                $body['refund_no'] = $refundModel->no;
                break;
            case 'delivery':
                /** @var InvoiceModel $invoiceModel */
                $invoiceModel = $model->invoice->makeHidden([
                    'id',
                    'order_id',
                    'shop_id',
                    'type',
                    'updated_at',
                    'postage_amount',
                    'best_at'
                ]);
                $body['invoice'] = $invoiceModel->toArray();
                break;
        }

        $query = [
            'timestamp' => time(),
            'app_id' => $appModel->app_id
        ];
        $query['sign'] = $appModel->encry(array_merge($query, $body));
        /** @var AppNotifyServices $appNotifyServices */
        $appNotifyServices = make(AppNotifyServices::class);
        $appNotifyModel = $appNotifyServices->create([
            'no' => $model->no,
            'url' => $appModel->payment_notify.'?'.http_build_query($query),
            'request_type' => 'post',
            'request_info' => $body,
            'scene' => $body['scene']
        ]);
        if (!$appNotifyModel->exists) {
            throw new InternalException();
        }
        /** @var NotifyQueue $notifyQueue */
        $notifyQueue = make(NotifyQueue::class);
        $notifyQueue->push([$appNotifyModel->id], Notify::class);
    }

    /**
     * 写入后操作
     * @author zx
     * @param Saved $saved
     */
    public function saved(Saved $saved)
    {
        /** @var static $model */
        $model = $saved->getModel();
        $change = $model->getChanges();

        logs($change);
        switch (Arr::get($change, 'pay_status')) {
            case OrderCode::PAY_STATUS_PAID: // 支付成功后操作
                defer(function () use ($model) {
                    try {
                        $model->addAction('订单付款', '订单付款成功');

                        $model->declaration();
                        /** @var App $appModel */
                        $appModel = $model->app;
                        if ($appModel->payment_notify) { // 如果配置了支付回调地址
                            $body = [
                                'no' => $model->no,
                                'merchant_no' => $model->merchant_no,
                                'transaction_id' => $model->transaction_id,
                                'paid_no' => $model->paid_no,
                                'paid_amount' => $model->paid_amount,
                                'status' => $model->status,
                                'status_text' => $model->status_text,
                                'pay_status' => $model->pay_status,
                                'pay_status_text' => $model->pay_status_text,
                                'scene' => 'payment',
                                'attach' => $model->attach,
                                'source' => $model->source
                            ];

                            $query = [
                                'timestamp' => time(),
                                'app_id' => $appModel->app_id
                            ];
                            $query['sign'] = $appModel->encry(array_merge($query, $body));
                            /** @var AppNotifyServices $appNotifyServices */
                            $appNotifyServices = make(AppNotifyServices::class);
                            $appNotifyModel = $appNotifyServices->create([
                                'no' => $model->no,
                                'url' => $appModel->payment_notify.'?'.http_build_query($query),
                                'request_type' => 'post',
                                'request_info' => $body,
                                'scene' => $body['scene']
                            ]);
                            if (!$appNotifyModel->exists) {
                                throw new InternalException();
                            }
                            /** @var NotifyQueue $notifyQueue */
                            $notifyQueue = make(NotifyQueue::class);
                            $notifyQueue->push([$appNotifyModel->id], Notify::class);
                        }

                        $model->pushErp();
                    } catch (\Throwable $throwable) {
                        logs($throwable->getMessage());
                        logs($throwable->getTraceAsString());
                    }
                });
                break;
            case OrderCode::PAY_STATUS_REFUND:
                defer(function () use ($model) {
                    try {
                        $model->addAction('订单取消', '您取消了订单');
                        /** @var App $appModel */
                        $appModel = $model->app;
                        if ($appModel->payment_notify) { // 如果配置了支付回调地址
                            /** @var Payment $refundModel */
                            $refundModel = $model->payment()
                                ->where('type', PaymentCode::TYPE_REFUND)
                                ->whereNotNull('process_at')
                                ->firstOrFail();
                            $body = [
                                'no' => $model->no,
                                'merchant_no' => $model->merchant_no,
                                'transaction_id' => $model->transaction_id,
                                'paid_amount' => $model->paid_amount,
                                'paid_no' => $model->paid_no,
                                'refund_amount' => $refundModel->amount,
                                'refund_no' => $refundModel->no,
                                'status' => $model->status,
                                'status_text' => $model->status_text,
                                'pay_status' => $model->pay_status,
                                'pay_status_text' => $model->pay_status_text,
                                'scene' => 'refund',
                                'attach' => $model->attach,
                                'source' => $model->source
                            ];
                            $query = [
                                'timestamp' => time(),
                                'app_id' => $appModel->app_id
                            ];
                            $query['sign'] = $appModel->encry(array_merge($query, $body));
                            /** @var AppNotifyServices $appNotifyServices */
                            $appNotifyServices = make(AppNotifyServices::class);
                            $appNotifyModel = $appNotifyServices->create([
                                'no' => $model->no,
                                'url' => $appModel->payment_notify.'?'.http_build_query($query),
                                'request_type' => 'post',
                                'request_info' => $body,
                                'scene' => $body['scene']
                            ]);
                            if (!$appNotifyModel->exists) {
                                throw new InternalException();
                            }
                            /** @var NotifyQueue $defaultQueue */
                            $notifyQueue = make(NotifyQueue::class);
                            $notifyQueue->push([$appNotifyModel->id], Notify::class);
                        }

                        $model->pushErp();
                    } catch (\Throwable $throwable) {
                        logs($throwable->getMessage());
                        logs($throwable->getTraceAsString());
                    }
                });
                break;
        }

        switch (Arr::get($change, 'status')) {
            case OrderCode::STATUS_PENDING_RECEIVED:

                break;
            case OrderCode::STATUS_RECEIVED:
                /** @var DefaultQueue $defaultQueue */
                $defaultQueue = make(DefaultQueue::class);
                $defaultQueue->push([$model->id], Complete::class, 60*60*24*7); // 收货七天后自动完成
                break;
        }
    }

    /**
     * 订单发货
     */
    public function delivery():void
    {
        $model = $this;
        // 订单发货
        defer(function () use ($model) {
            try {
                $model->addAction('订单发货', '您的订单已发货');

                /** @var App $appModel */
                $appModel = $model->app;
                /** @var InvoiceModel $invoiceModel */
                $invoiceModel = $model->invoice->makeHidden([
                    'id',
                    'order_id',
                    'shop_id',
                    'type',
                    'updated_at',
                    'postage_amount',
                    'best_at'
                ]);
                if ($appModel->payment_notify) { // 如果配置了支付回调地址
                    $body = [
                        'no' => $model->no,
                        'merchant_no' => $model->merchant_no,
                        'transaction_id' => $model->transaction_id,
                        'paid_amount' => $model->paid_amount,
                        'paid_no' => $model->paid_no,
                        'status' => $model->status,
                        'status_text' => $model->status_text,
                        'pay_status' => $model->pay_status,
                        'pay_status_text' => $model->pay_status_text,
                        'invoice' => $invoiceModel->toArray(),
                        'scene' => 'delivery',
                        'attach' => $model->attach,
                        'source' => $model->source
                    ];
                    $query = [
                        'timestamp' => time(),
                        'app_id' => $appModel->app_id
                    ];
                    $query['sign'] = $appModel->encry(array_merge($query, $body));
                    /** @var AppNotifyServices $appNotifyServices */
                    $appNotifyServices = make(AppNotifyServices::class);
                    $appNotifyModel = $appNotifyServices->create([
                        'no' => $model->no,
                        'url' => $appModel->payment_notify.'?'.http_build_query($query),
                        'request_type' => 'post',
                        'request_info' => $body,
                        'scene' => $body['scene']
                    ]);

                    /** @var NotifyQueue $notifyQueue */
                    $notifyQueue = make(NotifyQueue::class);
                    $notifyQueue->push([$appNotifyModel->id], Notify::class);

                    /** @var DefaultQueue $defaultQueue */
                    $defaultQueue = make(DefaultQueue::class);
                    $defaultQueue->push([$model->id], Complete::class, 60*60*24*7); // 七天后自动收货

                    $model->pushErp();
                }
            } catch (\Throwable $throwable) {
                logs($throwable->getMessage());
                logs($throwable->getTraceAsString());
            }
        });
    }

    /**
     * 支付申报
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function declaration(bool $isCache=true):void
    {
        if ($this->auto_erp === 0) return ;

        /** @var OrderDeclareModel $declareModel */
        $declareModel = $this->declares;

        /** @var Good $gosGoodOther */
//        $gosGoodOther = make(Good::class);
        /** @var OrderGoodModel $orderGoodModel */
//        $orderGoodModel = $this->goods()->firstOrFail();

//        $gosGood = $gosGoodOther->info($orderGoodModel->product_id, $isCache);

        /** @var Payment $paymentModel */
        $paymentModel = $this->payment()
            ->whereNotNull('process_at')
            ->where('type', 1)
            ->firstOrFail();
        $params = (new PaymentResource($paymentModel))->toPushOrderArray();

//        $params['planPushCustomCode'] = match (Arr::get($gosGood, 'warehouse_customs')) {
//            '2238' => 'SH',
//            default => 'SH'
//        };

        /** @var Factory $declarationFactory */
        $declarationFactory = make(Factory::class);

        try {
            if (!in_array($paymentModel->code, [
                'safepayMini'
            ])) {
                Context::set(
                    'pay_config_array',
                    config("cloud.payment.{$paymentModel->code}.{$this->shop_id}")
                );
            }

            [$request, $response, $body, $url] = $declarationFactory->{$paymentModel->code}($params);
            $data = [
                'status' => 1,
                'request_type' => 'post',
                'url' => $url,
                'request' => $request,
                'response' => $response
            ];
            if (in_array($this->pay_code, ['sumpayMini'])) {
                $data['paid_no'] = $params['order_no'];
            }
            if ($declareModel) {
                $declareModel->fill($data)->save();
            } else {
                $declareModel = $this->declares()->create($data);
            }
        } catch (\Throwable $throwable) {
            logs($throwable->getMessage());
            $data = [
                'status' => 2,
                'request_type' => 'post',
                'url' => '',
                'request' => $params,
                'response' => ['message' => $throwable->getMessage()]
            ];
            if ($declareModel) {
                $declareModel->fill($data)->save();
            } else {
                $declareModel = $this->declares()->create($data);
            }
        }
    }

    /**
     * 查询支付申报
     * @return array
     */
    public function toQueryDeclare(): array
    {
        /** @var Factory $declarationFactory */
        $declarationFactory = make(Factory::class);
        $action = $this->pay_code."Query";

        if (!in_array($this->pay_code, [
            'safepayMini'
        ])) {
            Context::set(
                'pay_config_array',
                config("cloud.payment.{$this->pay_code}.{$this->shop_id}")
            );
        }

        $params = (new OrderResource($this))->toQueryDeclareArray();
        return $declarationFactory->{$action}($params);
    }

    /**
     * 推送数据到ERP
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function pushErp(bool $force=false)
    {
        if ($force === false && $this->auto_erp === 0) return ;

        $data = $this->toErpArray();
        /** @var Push $push */
        $push = make(Push::class);
        $push->handle([
            'trades' => json_encode([$data], JSON_UNESCAPED_UNICODE)
        ]);

//        $snapshot = $this->toSnapshotArray();
//        /** @var Snapshot $snapshotPush */
//        $snapshotPush = make(Snapshot::class);
//        $snapshotPush->push(['orderArr' => [$snapshot]]);
    }

    /**
     * 获取erp数据
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function toErpArray():array
    {
        $orderData = [];
        $orderGoodModels = $this->goods;
        $statusArr = [
            OrderCode::STATUS_PENDING_PAID => 1,
            OrderCode::STATUS_PENDING_DELIVERY => 2,
            OrderCode::STATUS_PENDING_RECEIVED => 3,
            OrderCode::STATUS_RECEIVED => 3,
            OrderCode::STATUS_COMPLETE => 3,
            OrderCode::STATUS_CLOSE => 4,
            OrderCode::STATUS_CANCEL => 4
        ];
        $status = $statusArr[$this->status];
        /** @var OrderGoodModel $orderGoodModel */
        foreach ($orderGoodModels as $key => $orderGoodModel) {
            $orderData[] = [
                'tradeID' => $this->paid_no,
                'orderID' => $this->merchant_no.'_'.$key,
                'itemID' => $orderGoodModel->product_id,
                'itemCode' => $orderGoodModel->good_no,
                'itemTitle' => $orderGoodModel->good['name'],
                'skuTitle' => '',
                'status' => $status,
                'price' => $orderGoodModel->paid_price,
                'size' => $orderGoodModel->num,
                'imageUrl' => $orderGoodModel->good['image'],
                'payment' => bcmul((string)$orderGoodModel->paid_price, (string)$orderGoodModel->num, 2),
                'snapshot' => $orderGoodModel->snapshot
            ];
        }

        $statusArr = [
            OrderCode::STATUS_PENDING_PAID => 1,
            OrderCode::STATUS_PENDING_DELIVERY => 2,
            OrderCode::STATUS_PENDING_RECEIVED => 5,
            OrderCode::STATUS_RECEIVED => 6,
            OrderCode::STATUS_COMPLETE => 3,
            OrderCode::STATUS_CLOSE => 4,
            OrderCode::STATUS_CANCEL => 4
        ];
        $status = $statusArr[$this->status];

        switch ($status) {
            case 3:
                $time = ['endTime', strtotime($this->complete_at) * 1000];
                break;
            case 4:
                $time = ['endTime', ($this->refund_at?strtotime($this->refund_at):$this->updated_at->getPreciseTimestamp(0)) * 1000];
                break;
            case 5:
                $time = ['shippingTime', strtotime($this->shipping_at) * 1000];
                break;
            default:
                $time = ['payTime', strtotime($this->paid_at) * 1000];
                break;
        }

        /** @var Good $gosGoodOther */
        $gosGoodOther = make(Good::class);
        /** @var OrderGoodModel $orderGoodModel */
        $orderGoodModel = $this->goods()->firstOrFail();
        $gosGood = $gosGoodOther->info($orderGoodModel->product_id);
        $invoiceModel = $this->invoice()->orderBy('id', 'desc')->first();

        $payCode = match ($this->payment()->where('type', PaymentCode::TYPE_PAYMENT)->value('code')) {
            'safepayMini', 'neopayMini', 'neopayWechat' => 'NeoPay',
            'wechatMini' => 'Wechat', 'sumpayMini' => 'SumPay',
            'chinapnrpayMini' => 'CHINAPNR'
        };

        return [
            'tradeID' => $this->paid_no,
            'shopNick' => $this->shop->name,
            'status' => $status,
            'createTime' => $this->created_at->getPreciseTimestamp(3),
            $time[0] => $time[1],
            'modifyTime' => $this->updated_at->getPreciseTimestamp(3),
            'shippingType' => 0,
            'storeID' => $gosGood['warehouse_code']??'YWCY',
            'buyerMessage' => $this->user_note,
            'totalFee' => $this->discount_amount?(array_sum($this->discount_amount)+$this->paid_amount):$this->paid_amount,
            'postFee' => $this->postage_amount,
            'clearance_discount' => $this->discount_amount?array_sum($this->discount_amount):0,
            'payment' => $this->paid_amount,
            'discountFee' => $this->discount_amount?array_sum($this->discount_amount):0,
            'buyer' => $this->payer['id']??md5($this->payer_no),
            'receiverName' => $this->consignee,
            'receiverProvince' => $this->prov,
            'receiverCity' => $this->city,
            'receiverArea' => $this->area,
            'receiverAddress' => $this->address,
            'receiverMobile' => $this->mobile,
            'logisticsName' => $invoiceModel?$invoiceModel->logistics_name:'',
            'logisticsCode' => $invoiceModel?$invoiceModel->logistics_code:'',
            'expressCode' => $invoiceModel?$invoiceModel->logistics_no:'',
            'hasRefund' => $this->pay_status === OrderCode::PAY_STATUS_REFUND ? 1 : 0,
            'payNo' => $this->transaction_id,
            'payType' => $payCode,
            'identityNum' => $this->payer_no,
            'identityName' => $this->payer_name,
            'sellerMemo' => $this->merchant_no,
            'orders' => $orderData
        ];
    }

    /**
     * 获取快照数据
     * @return array
     */
    public function toSnapshotArray():array
    {
        $snapshotArray = [];
        $orderGoodModels = $this->goods;
        /** @var OrderGoodModel $orderGoodModel */
        foreach ($orderGoodModels as $orderGoodModel) {
            $snapshotArray[] = [
                'goodsId' => $orderGoodModel->product_id,
                'snapshot' => $orderGoodModel->snapshot,
                'snapshotStorageUrl' => $orderGoodModel->product_link
            ];
        }
        return [
            'orderId' => $this->paid_no,
            'snapshotArray' => $snapshotArray
        ];
    }

    /**
     * 查询订单号码
     * @param $query
     * @param $value
     * @param string $alias
     */
    public function scopeNo($query, $value, $alias='')
    {
        $query->where($this->getAlias($alias, 'no'), $value);
    }

    /**
     * 查询订单号码
     * @param $query
     * @param $value
     * @param string $alias
     */
    public function scopeOrderId($query, $value, $alias='')
    {
        $query->where($this->getAlias($alias, 'merchant_no'), $value);
    }

    /**
     * 查询商户订单号码
     * @param $query
     * @param $value
     * @param string $alias
     */
    public function scopeMerchantNo($query, $value, $alias='')
    {
        $query->where($this->getAlias($alias, 'merchant_no'), $value);
    }

    /**
     * 查询支付状态
     * @param $query
     * @param $value
     * @param string $alias
     */
    public function scopePayStatus($query, $value, $alias='')
    {
        $query->where($this->getAlias($alias, 'pay_status'), $value);
    }

    /**
     * 查询订单状态
     * @param $query
     * @param $value
     * @param string $alias
     */
    public function scopeStatus($query, $value, $alias='')
    {
        $query->where($this->getAlias($alias, 'status'), $value);
    }

    /**
     * 查询联系人
     * @param $query
     * @param $value
     * @param string $alias
     */
    public function scopeConsignee($query, $value, $alias='')
    {
        $query->where($this->getAlias($alias, 'consignee'), $value);
    }

    /**
     * 查询联系人
     * @param $query
     * @param $value
     * @param string $alias
     */
    public function scopeMobile($query, $value, $alias='')
    {
        $query->where($this->getAlias($alias, 'mobile'), $value);
    }

    /**
     * 支付人姓名搜索器
     * @param $query
     * @param $value
     * @param string $alias
     */
    public function scopePayerName($query, $value, $alias='')
    {
        $query->where($this->getAlias($alias, 'payer_name'), $value);
    }

    /**
     * 支付人证件搜索器
     * @param $query
     * @param $value
     * @param string $alias
     */
    public function scopePayerNo($query, $value, $alias='')
    {
        $query->where($this->getAlias($alias, 'payer_no'), $value);
    }

    /**
     * 获取179号企业报文
     * @return array
     */
    public function toNo179Array():array
    {
        /** @var Payment $paymentModel */
        $paymentModel = $this->payment()
            ->where('type', PaymentCode::TYPE_PAYMENT)
            ->whereNotNull('process_at')
            ->firstOrFail();

        $params['payExchangeInfoHead'] = [
            'guid' => $this->paid_no,
            'initalRequest' => json_encode($paymentModel->request_body, JSON_UNESCAPED_UNICODE),
            'initalResponse' => json_encode($paymentModel->response_body, JSON_UNESCAPED_UNICODE),
            'ebpCode' => '312066000G',
            'payCode' => match ($paymentModel->code) {'safepayMini' => '120436402L'},
            'payTransactionId' => $this->transaction_id,
            'totalAmount' => $this->paid_amount,
            'currency' => '142',
            'verDept' => 3,
            'payType' => 4,
            'tradingTime' => date('YmdHis', strtotime($this->paid_at)),
            'note' => $this->user_note
        ];

        $goods = [];
        /** @var OrderGood $orderGoodModel */
        foreach ($this->goods as $orderGoodModel) {
            $goods[] = $orderGoodModel->toExchangeInfoArray();
        }

        $params['payExchangeInfoLists'][] = [
            'orderNo' => $this->paid_no,
            'goodsInfo' => $goods,
            'recpName' => '上海数析信息技术有限公司',
            'recpAccount' => '6225882582810987'
        ];

        return $params;
    }

    /**
     * 去支付
     * @param array $input
     * @return array
     */
    public function goPay(array $input): array
    {
        /** @var \App\Factory\Payment\Factory $factory */
        $factory = make(\App\Factory\Payment\Factory::class);

        $param = (new OrderResource($this))->toPayArray();

        if (!in_array($this->pay_code, ['safepayMini'])) {
            Context::set('pay_config_array', config("cloud.payment.{$this->pay_code}.{$this->shop_id}"));
        }

        [$request, $response, $responseParams] = $factory->{$this->pay_code}($param, Arr::get($this->payer, 'app_id', ''));

        $no = match ($this->pay_code) {
            'sandpayMini' => $responseParams['outOrderNo'],
            'safepayMini' => $response['data']['trace'],
            'neopayMini', 'neopayWechat' => $response['trace'],
            default => $this->merchant_no
        };

        $this->payment()->create([
            'order_no' => $this->no,
            'amount' => $this->paid_amount,
            'no' => $no,
            'user_id' => $this->user_id,
            'request_body' => $request,
            'response_body' => $response,
            'type' => PaymentCode::TYPE_PAYMENT,
            'code' => $this->pay_code
        ]);
        $this->fill(['paid_no' => $no])->save();

        $responseParams = match ($this->pay_code) {
            'sandpayMini' => $responseParams['credential'],
            'neopayMini', 'neopayWechat' => $responseParams['resultContent'],
            'wechatMini' => json_encode($responseParams, JSON_UNESCAPED_UNICODE),
            default => $responseParams
        };

        return [$request, $response, $responseParams];
    }

    /**
     * 查询支付订单
     * @param array $input
     * @return array
     */
    public function queryPaymentOrder(array $input): array
    {
        /** @var \App\Factory\Query\Factory $factory */
        $factory = make(\App\Factory\Query\Factory::class);

        if (!in_array($this->pay_code, ['safepayMini'])) {
            Context::set('pay_config_array', config("cloud.payment.{$this->pay_code}.{$this->shop_id}"));
        }

        $param = (new OrderResource($this))->toQueryArray();

        [,,$responseParams] = $factory->{$this->pay_code}($param);

        return $responseParams;
    }
}
